package com.heima.article.service.impl;

import ch.qos.logback.core.util.StringCollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heima.article.entity.ApArticle;
import com.heima.article.entity.ApArticleContent;
import com.heima.article.entity.ApAuthor;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.mapper.ApAuthorMapper;
import com.heima.article.service.ApArticleContentService;
import com.heima.article.service.ApArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.service.FreemarkerService;
import com.heima.common.dtos.ApArticleDto;
import com.heima.common.dtos.FindNewsCommentsDto;
import com.heima.common.dtos.PageResult;
import com.heima.common.util.BeanHelper;
import com.heima.common.util.JsonUtils;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.ArticleLoadDTO;
import com.heima.model.media.dtos.WmNewsResultDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 文章信息表，存储已发布的文章 服务实现类
 * </p>
 *
 * @author HM
 * @since 2023-05-25
 */
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {

    @Autowired
    private ApArticleContentService contentService;

    @Autowired
    private FreemarkerService freemarkerService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ApAuthorMapper apAuthorMapper;

    @Override
    public List<ApArticle> findLatestArticlesIn(int days) {
        LocalDateTime startTime = LocalDate.now().minusDays(days).atStartOfDay();
        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApArticle::getIsDelete, false);
        queryWrapper.eq(ApArticle::getIsDown, false);
        //发布时间
        queryWrapper.ge(ApArticle::getPublishTime, startTime);
        return this.list(queryWrapper);
    }

    @Override
    public PageResult<ApArticleDto> findNewsComments(FindNewsCommentsDto dto) {

        LambdaQueryWrapper<ApAuthor> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(ApAuthor::getWmUserId,dto.getUserId());
        ApAuthor apAuthor = apAuthorMapper.selectOne(queryWrapper1);

        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
        if (dto.getBeginDate() != null){
            queryWrapper.ge(ApArticle::getCreatedTime,dto.getBeginDate());
        }
        if (dto.getEndDate() != null){
            queryWrapper.le(ApArticle::getCreatedTime,dto.getEndDate());
        }

        queryWrapper.eq(ApArticle::getAuthorId,apAuthor.getId());
        Page<ApArticle> page = new Page<>(dto.getPage(),dto.getSize());
        Page<ApArticle> articlePage = this.page(page, queryWrapper);
        List<ApArticle> articleList = articlePage.getRecords();

        List<ApArticleDto> articleDtos = articleList.stream().map(apArticle -> {
            ApArticleDto apArticleDto = new ApArticleDto();
            apArticleDto.setId(apArticle.getId());
            apArticleDto.setTitle(apArticle.getTitle());
            apArticleDto.setComments(apArticle.getComments());
            apArticleDto.setIsComment(apArticle.getIsComment());
            apArticleDto.setCreatedTime(apArticle.getCreatedTime());
            return apArticleDto;
        }).collect(Collectors.toList());

        return new PageResult(articlePage.getCurrent(),articlePage.getSize(),articlePage.getTotal(),articleDtos);
    }

    @Override
    public ArticleDto findById(long articleId) {
        return this.baseMapper.findById(articleId);
    }

    @Override
    public List<ArticleDto> findByPage(int page, int size) {
        Page<ApArticle>  ipage = new Page<>(page, size);
        return this.baseMapper.findByPage(ipage);
    }

    @Override
    public List<ApArticle> load(ArticleLoadDTO dto) {
        return loadmore(dto);
    }

    @Override
    public List<ApArticle> loadmore(ArticleLoadDTO dto) {
        // 如果是推荐频道，查询redis的zset
        if(dto.getChannelId() != null && dto.getChannelId() == 0){
            return loadHotArticles(dto);
        }
        // 比当前页，最小的还要小
        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
        // 默认的过滤条件
        queryWrapper.eq(ApArticle::getIsDown, false);
        queryWrapper.eq(ApArticle::getIsDelete, false);
        queryWrapper.lt(ApArticle::getPublishTime, dto.getMinTime());
        queryWrapper.eq(dto.getChannelId()!=null && dto.getChannelId()>0, ApArticle::getChannelId, dto.getChannelId());
        // 添加发布时间的排序
        queryWrapper.orderByDesc(ApArticle::getPublishTime);
        // limit ?
        Page<ApArticle> ipgae= new Page<>(1, dto.getSize());
        // 查询
        Page<ApArticle> pageResponse = this.page(ipgae, queryWrapper);
        return pageResponse.getRecords();
    }

    @Override
    public List<ApArticle> loadnew(ArticleLoadDTO dto) {
        // 如果是推荐频道，查询redis的zset
        if(dto.getChannelId() != null && dto.getChannelId() == 0){
            return loadHotArticles(dto);
        }
        // 比当前页最大的数据还要大
        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApArticle::getIsDown, false);
        queryWrapper.eq(ApArticle::getIsDelete, false);
        queryWrapper.gt(ApArticle::getPublishTime, dto.getMaxTime());
        queryWrapper.eq(dto.getChannelId()!=null && dto.getChannelId()>0, ApArticle::getChannelId, dto.getChannelId());
        // 添加发布时间的排序
        queryWrapper.orderByDesc(ApArticle::getPublishTime);
        // limit ?
        Page<ApArticle> ipgae= new Page<>(1, dto.getSize());
        // 查询
        Page<ApArticle> pageResponse = this.page(ipgae, queryWrapper);
        return pageResponse.getRecords();
    }

    // TODO zset手机端的分页
    private List<ApArticle> loadHotArticles(ArticleLoadDTO dto) {
        Set<String> articleIds = redisTemplate.boundZSetOps(ApHotArticlesServiceImpl.PREFIX).reverseRangeByScore(0, Double.MAX_VALUE);
        if(CollectionUtils.isEmpty(articleIds)){
            return new ArrayList<>();
        }
        List<ApArticle> result = new ArrayList<>(articleIds.size());
        for(String articleId : articleIds){
            //TODO article上下架的时候，redis需要同步上下架
            String json = redisTemplate.boundValueOps(ApHotArticlesServiceImpl.PREFIX + ":" + articleId).get();
            if(!StringUtils.isEmpty(json)){
                ApArticle article = JsonUtils.toBean(json, ApArticle.class);
                result.add(article);
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createArticle(WmNewsResultDTO dto) {
        // 跟据自媒体文章的id查询article，有就更新，没有就插入
        // 保存ap_article，saveOrUpdate
        Long articleId = saveArticle(dto);
        // 保存ap_article_content，saveOrUpdate
        contentService.saveContent(articleId, dto.getContent());
        // 异步 生成静态的html，上传minio，回填url地址到ap_article
        freemarkerService.asyncContentStatic(articleId, dto.getContent());
        return articleId;
    }

    private Long saveArticle(WmNewsResultDTO dto) {
        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApArticle::getWmNewsId, dto.getId());
        ApArticle articleDB = this.getOne(queryWrapper);
        Long articleId = 0L;
        if(articleDB == null){
            // insert
            ApArticle toBeInsert = BeanHelper.copyProperties(dto, ApArticle.class);
            toBeInsert.setId(null);
            toBeInsert.setAuthorId(123);//TODO 根据wmUserId查询author数据
            toBeInsert.setAuthorName("123");
            toBeInsert.setLayout(dto.getType());
            toBeInsert.setFlag(0);
            toBeInsert.setLikes(0L);
            toBeInsert.setComments(0L);
            toBeInsert.setCollection(0L);
            toBeInsert.setViews(0L);
            toBeInsert.setCreatedTime(new Date());
            toBeInsert.setIsComment(true);
            toBeInsert.setIsForward(true);
            toBeInsert.setIsDelete(false);
            toBeInsert.setIsDown(false);
            toBeInsert.setWmNewsId(dto.getId());
            this.save(toBeInsert);
            articleId = toBeInsert.getId();
        }else{
            // update
            ApArticle toBeUpdate =  BeanHelper.copyProperties(dto, ApArticle.class);
            toBeUpdate.setId(articleDB.getId());
            toBeUpdate.setLayout(dto.getType());
            this.updateById(toBeUpdate);
            articleId = articleDB.getId();
        }
        return articleId;
    }

}
